package com.xuecheng.comment.service.serviceImpl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.api.comment.model.dto.CommentDTO;
import com.xuecheng.api.comment.model.qo.CommentConditionModel;
import com.xuecheng.api.comment.model.vo.CommentStatisticsVo;
import com.xuecheng.api.search.model.dto.CoursePubIndexDTO;
import com.xuecheng.comment.agent.SearchApiAgent;
import com.xuecheng.comment.common.constant.CommentErrorCode;
import com.xuecheng.comment.convert.CommentConvert;
import com.xuecheng.comment.convert.CommentReplyConvert;
import com.xuecheng.comment.entity.Comment;
import com.xuecheng.comment.entity.CommentReply;
import com.xuecheng.comment.mapper.CommentMapper;
import com.xuecheng.comment.mapper.CommentReplyMapper;
import com.xuecheng.comment.service.CommentService;
import com.xuecheng.common.domain.code.CommonErrorCode;
import com.xuecheng.common.domain.page.PageRequestParams;
import com.xuecheng.common.domain.page.PageVO;
import com.xuecheng.common.domain.response.RestResponse;
import com.xuecheng.common.enums.common.CommonEnum;
import com.xuecheng.common.exception.ExceptionCast;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author itcast
 * @since 2019-10-31
 */
@Slf4j
@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {

    @Autowired
    private CommentReplyMapper commentReplyMapper;

    @Autowired
    private SearchApiAgent searchApiAgent;

    @Autowired
    private CommentMapper commentMapper;

    @Transactional
    public RestResponse<CommentDTO> addComment(CommentDTO commentDTO) {

        Comment comment = CommentConvert.INSTANCE.dto2entity(commentDTO);

        comment.setCommentDate(LocalDateTime.now());

        comment.setStatus(CommonEnum.USING_FLAG.getCodeInt());

        commentDTO.setStarRank(commentDTO.getStarRank());

        comment.setId(null);

        boolean result = this.save(comment);


        if (!result) {
            return RestResponse.validfail(CommentErrorCode.E_180001);
        }

        CommentDTO dto = CommentConvert.INSTANCE.entity2dto(comment);

        return RestResponse.success(dto);

    }


    @Transactional(readOnly = true)
    public RestResponse<PageVO<CommentDTO>> list(PageRequestParams params, CommentConditionModel commentModel, Boolean company) {

        //判断参数合法性
        //ExceptionCast.cast(commentModel == null || StringUtils.isBlank(commentModel.getComeFrom()), CommonErrorCode.E_100101);
        if (ObjectUtils.isEmpty(commentModel) || StringUtils.isBlank(commentModel.getComeFrom())) {
            //微服务远程调用异常
            return RestResponse.validfail(CommonErrorCode.E_100101);
        }

        //设置查询条件
        LambdaQueryWrapper<Comment> wrapper = new LambdaQueryWrapper<>();

        //锁定评论对象
        wrapper.eq(commentModel.getTargetId() != null, Comment::getTargetId, commentModel.getTargetId());

        //锁定评论类型
        wrapper.eq(StringUtils.isNotBlank(commentModel.getTargetType()), Comment::getTargetType, commentModel.getTargetType());

        //company=true:必须有教学机构
        if (company) {
            if (ObjectUtils.isEmpty(commentModel.getBelongTo())) {
                return RestResponse.validfail(CommonErrorCode.E_100108);
            }
        }
        //锁定归属的教育机构
        wrapper.eq(commentModel.getBelongTo() != null, Comment::getBelongTo, commentModel.getBelongTo());

        //是否有评论对象名称查询条件
        if (StringUtils.isNotBlank(commentModel.getTargetName())) {
            wrapper.like(Comment::getTargetName, commentModel.getTargetName());
        }

        //根据回复状态Y/N查询
        if (StringUtils.isNotBlank(commentModel.getReplyStatus()) && commentModel.getReplyStatus().equalsIgnoreCase("Y")) {

            wrapper.eq(Comment::getReplyStatus, CommonEnum.USING_FLAG.getCode());

        } else if (StringUtils.isNotBlank(commentModel.getReplyStatus()) && commentModel.getReplyStatus().equalsIgnoreCase("N")) {

            wrapper.eq(Comment::getReplyStatus, CommonEnum.DELETE_FLAG.getCode());

        }

        /*
         * 根据评论级别查询
         * 评价级别1好评:StarRank>3
         *       0中评 :StarRank=3
         *       -1差评:StarRank<3
         * */
        if (commentModel.getLevel() != null) {

            if (commentModel.getLevel().intValue() == 1) {

                wrapper.gt(Comment::getStarRank, 3);

            } else if (commentModel.getLevel().intValue() == 0) {

                wrapper.eq(Comment::getStarRank, 3);

            } else if (commentModel.getLevel().intValue() == -1) {

                wrapper.lt(Comment::getStarRank, 3);

            }

        }

        //评论来源[即来自于那个应用]
        wrapper.eq(Comment::getComeFrom, commentModel.getComeFrom());

        //评论隐藏还是显示
        wrapper.eq(Comment::getStatus, CommonEnum.USING_FLAG.getCode());

        //分页查询
        IPage<Comment> iPage = this.page(new Page<>(params.getPageNo(), params.getPageSize()), wrapper);

        //创建结果对象
        RestResponse<PageVO<CommentDTO>> response = new RestResponse<>();
        PageVO<CommentDTO> result = new PageVO<>(iPage.getTotal(), iPage.getCurrent(), iPage.getSize());

        //判断分页数据是否存在
        if (iPage.getRecords() != null && iPage.getRecords().size() > 0) {

            List<CommentDTO> commentDTOS = CommentConvert.INSTANCE.entitys2dtos(iPage.getRecords());

            for (CommentDTO commentDTO : commentDTOS) {

                //查询每条评论的回复
                LambdaQueryWrapper<CommentReply> wrapper_1 = new LambdaQueryWrapper<>();

                wrapper_1.eq(CommentReply::getCommentId, commentDTO.getCommentId());

                List<CommentReply> commentReplies = commentReplyMapper.selectList(wrapper_1);

                //为每条评论设置回复列表
                commentDTO.setReplyDTOList(CommentReplyConvert.INSTANCE.entitys2dtos(commentReplies));

            }

            //封装评论数据
            result.setItems(commentDTOS);
            response.setResult(result);

        }

        return response;

    }


    /*
    简单点，不用树形的层级机构展示评论及回复
    private List<CommentReplyDTO> makeCommentReplyTree(List<CommentReply> commentReplies) {
        List<CommentReplyDTO> replyDTOS = new ArrayList<>();
        if (!CollectionUtils.isEmpty(commentReplies)) {
            for (CommentReply commentReply : commentReplies) {
                if (commentReply.getParentId().longValue() == 0) {
                    CommentReplyDTO replyDTO = CommentReplyConvert.INSTANCE.entity2dto(commentReply);
                    replyDTOS.add(replyDTO);
                    recurCommentReplyTree(replyDTO, commentReplies);
                }
            }
        }
        return replyDTOS;
    }

    private void recurCommentReplyTree(CommentReplyDTO dto, List<CommentReply> commentReplies) {
        for (CommentReply cr : commentReplies) {
            if(cr.getParentId().equals(dto.getReplyId())) {
                dto.getReplyDTOList().add(CommentReplyConvert.INSTANCE.entity2dto(cr));
            }
        }
        if (!CollectionUtils.isEmpty(dto.getReplyDTOList())) {
            for (CommentReplyDTO tmp : dto.getReplyDTOList()) {
                recurCommentReplyTree(tmp, commentReplies);
            }
        }
    }*/


    @Transactional
    public RestResponse<CommentDTO> delComment(Long commentId) {
        //判断关键数据
        ExceptionCast.cast(commentId == null, CommonErrorCode.E_100101);
        //查询评论
        LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.eq(Comment::getId, commentId);

        //   queryWrapper.eq(Comment::getComeFrom, comeFrom);

        Comment comment = this.getOne(queryWrapper);

        if (comment == null) {

            return RestResponse.validfail(CommonErrorCode.E_110008);

        }
        boolean result = this.removeById(commentId);
        if (!result) {
            return RestResponse.validfail(CommonErrorCode.E_110011);
        }
        LambdaQueryWrapper<CommentReply> queryWrapper_1 = new LambdaQueryWrapper<>();

        queryWrapper_1.eq(CommentReply::getCommentId, commentId);

        int count = commentReplyMapper.delete(queryWrapper_1);
        if (count < 1) {
            return RestResponse.validfail(CommonErrorCode.E_110011);
        }

        CommentDTO commentDTO = CommentConvert.INSTANCE.entity2dto(comment);
        RestResponse<CommentDTO> success = RestResponse.success(commentDTO);

        return success;

    }


    @Transactional
    public RestResponse<Boolean> batchDelComment(List<Long> commentIds) {

        ExceptionCast.cast(CollectionUtils.isEmpty(commentIds), CommonErrorCode.E_100101);

        LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.in(Comment::getId, commentIds);

        List<Comment> list = this.list(queryWrapper);

        if (CollectionUtils.isEmpty(list)) {

            return RestResponse.success(false);

        }

        boolean removed = this.remove(queryWrapper);

        List<Long> collect = list.stream().map(Comment::getId).collect(Collectors.toList());

        LambdaQueryWrapper<CommentReply> queryWrapper_1 = new LambdaQueryWrapper<>();

        queryWrapper_1.in(CommentReply::getCommentId, collect);

        commentReplyMapper.delete(queryWrapper_1);

        return RestResponse.success(removed);

    }

    /*评论点赞*/
    @Transactional
    public RestResponse<CommentDTO> praise(Long commentId) {
        //判断关键数据
        if (ObjectUtils.isEmpty(commentId)) {
            return RestResponse.validfail(CommonErrorCode.E_100101);
        }
        //该评论是否存在
        Comment comment = this.getById(commentId);
        if (ObjectUtils.isEmpty(comment)) {
            return RestResponse.validfail(CommonErrorCode.E_100104);
        }
        //查询当前评论点赞数量，修改评论数量
        Integer num = comment.getPraiseNum();
        comment.setPraiseNum(num + 1);
        boolean result = this.save(comment);
        if (!result) {
            return RestResponse.validfail(CommonErrorCode.E_110009);
        }
        CommentDTO dto = CommentConvert.INSTANCE.entity2dto(comment);
        RestResponse<CommentDTO> success = RestResponse.success(dto);
        return success;
    }

    /*
     * 统计
     * */
    @Override
    public RestResponse<CommentStatisticsVo> getCommentStatistics(Long coursePubId) {
        //创建统计数据模型
        CommentStatisticsVo result = new CommentStatisticsVo();

        //判断参数是否合法
        if (ObjectUtils.isEmpty(coursePubId)) {
            return RestResponse.validfail(CommonErrorCode.E_100101);
        }

        //查询发布的课程-远程调用
        RestResponse<CoursePubIndexDTO> response = searchApiAgent.getCoursePubIndexById4s(coursePubId);
        //判断远程调用是否成功
        if (!(response.isSuccessful())) {
            return RestResponse.validfail(CommentErrorCode.E_180002);
        }
        //获取发布信息
        CoursePubIndexDTO indexDTO = response.getResult();

        //判断课程发布数据是否存在
        if (ObjectUtils.isEmpty(indexDTO)) {
            return RestResponse.validfail(CommentErrorCode.E_180002);
        }

        Integer targetId = coursePubId.intValue();
        //根据课程发布id查询所有的评论
        LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Comment::getTargetId, targetId);

        //统计评论总数
        int totalCommentNums = this.count(queryWrapper);
        result.setTotalCommentNums((long) totalCommentNums);

        //查询总评分数
//        Map<String, Object> map = commentMapper.getStarRankNums(targetId);
//        Object total = map.get("total");
//        int starRankNums = (int) total;

        QueryWrapper<Comment> totalQueryWrapper = new QueryWrapper<>();
        totalQueryWrapper.select("sum(star_rank) as totalScore");
        totalQueryWrapper.eq("target_id", targetId);
        Map<String, Object> map = this.getMap(totalQueryWrapper);
        BigDecimal totalScore = (BigDecimal) map.get("totalScore");
        int starRankNums = totalScore.intValue();


        if (totalCommentNums == 0) {
            totalCommentNums = 1;
        }
        if (ObjectUtils.isEmpty(starRankNums)) {
            starRankNums = 0;
        }
        //获取平均分数
        int starRank = starRankNums / totalCommentNums;
        result.setStarRank((long) starRank);

        //查询评论1星的总数
        int starRank1Nums = getstarRankNums(targetId, 1);
        result.setStarRank1Nums((long) starRank1Nums);
        //查询评论2星的总数
        int starRank2Nums = getstarRankNums(targetId, 2);
        result.setStarRank2Nums((long) starRank2Nums);
        //查询评论3星的总数
        int starRank3Nums = getstarRankNums(targetId, 3);
        result.setStarRank3Nums((long) starRank3Nums);
        //查询评论4星的总数
        int starRank4Nums = getstarRankNums(targetId, 4);
        result.setStarRank4Nums((long) starRank4Nums);
        //查询评论5星的总数
        int starRank5Nums = getstarRankNums(targetId, 5);
        result.setStarRank5Nums((long) starRank5Nums);

        //返回数据
        return RestResponse.success(result);
    }

    private int getstarRankNums(Integer targetId, Integer starRank) {
        //查询各个星级的总数
        LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Comment::getTargetId, targetId);
        queryWrapper.eq(Comment::getStarRank, starRank);

        //统计评论总数
        return this.count(queryWrapper);
    }

    /**
     * 1.判断关键数据
     * commentId
     * 2.根据 commentId 获得comment数据并判断
     * 3.po转dto封装数据并返回
     */
    public RestResponse<CommentDTO> getCommentById(Long commentId) {
        //1.判断关键数据
        if (ObjectUtils.isEmpty(commentId)) {
            return RestResponse.validfail(CommonErrorCode.E_100101);
        }
        //2.根据 commentId 获得comment数据并判断
        Comment comment = this.getById(commentId);
        if (ObjectUtils.isEmpty(comment)) {
            RestResponse.validfail(CommentErrorCode.E_180101);
        }
        //3.po转dto封装数据并返回
        CommentDTO commentDTO = CommentConvert.INSTANCE.entity2dto(comment);

        return RestResponse.success(commentDTO);
    }

}
